package org.eclipse.java.generation;


import java.util.ArrayList;
import java.lang.Object;
import org.eclipse.gmt.modisco.java.Statement;
import org.eclipse.gmt.modisco.java.VariableDeclaration;

import artefact.umlClassDiagram.CreateAttribute;
import artefact.umlClassDiagram.CreateClass;
import artefact.umlClassDiagram.CreateGeneralization;
import artefact.umlClassDiagram.CreateInterface;
import artefact.umlClassDiagram.CreateOperation;
import artefact.umlClassDiagram.CreateOperationRefinement;
import artefact.umlClassDiagram.CreateStatement;
import artefact.umlClassDiagram.impl.CreateAttributeImpl;
import artefact.umlClassDiagram.impl.CreateStatementImpl;

import fr.lip6.meta.ple.featureIdentification.Feature;
import fr.lip6.meta.ple.generation.fh.java.ReadXmiFHJava;
import fr.lip6.meta.tools.StatementPrimitive;
import fr.lip6.meta.tools.Trigger;

public class FeatureToCode {

	/**
	 * @param args
	 * 
	 */

	public static ArrayList<String> allclass =new ArrayList<String>();
	public static ArrayList<String> allattributtes =new ArrayList<String>();
	public static ArrayList<String> allmethods =new ArrayList<String>();
	public static ArrayList<String> allinterface =new ArrayList<String>();
	public static ArrayList<String> allStatements =new ArrayList<String>();
	public static ArrayList<String> allStatementsAjout = new ArrayList<String>();

	public static ArrayList<String> allStatementsBase = new ArrayList<String>();
	public static ArrayList<String> allMethdeBase = new ArrayList<String>();
	public static Feature featureBase = null;

	public static String feautreName="F0";
	public static int i=0;
	public static String currentclass="";
	public static String currentPackage="";
	public static Feature currentfeature;
	public static boolean first=false;
	public static boolean isoriginal=false;

	/**
	 * Initialise las paramètres de features
	 * @param feat : Feature
	 */
	public static void init(Feature feat)
	{
		allclass.clear();
		allmethods.clear();
		allattributtes.clear();
		allinterface.clear();
		allStatements.clear();
		allStatementsAjout.clear();
		first=false;
		isoriginal = false;
		currentfeature=feat;
	}

	/**
	 * 
	 * @return
	 */
	public boolean getAllClassNamesInFeature()
	{     
		if(!first)
		{
			try
			{
				for(Trigger t : currentfeature)
				{
					StatementPrimitive st = (StatementPrimitive)t;
					if (st.getPrimitive() instanceof CreateClass)
					{
						CreateClass c=(CreateClass) st.getPrimitive();
						allclass.add(c.getName()+".java");
					}

					if (st.getPrimitive() instanceof CreateGeneralization)
					{
						CreateGeneralization c=(CreateGeneralization) st.getPrimitive();
						allclass.add(c.getSub()+".java");
					}

					if(st.getPrimitive() instanceof CreateInterface)
					{
						CreateInterface in=(CreateInterface) st.getPrimitive();
						allinterface.add(in.getName()+".java");
					}

					if (st.getPrimitive() instanceof CreateOperation)
					{
						CreateOperation o=(CreateOperation) st.getPrimitive();
						allmethods.add(o.getName()+"::"+o.getOwener()+".java");

						if(!allclass.contains(o.getOwener()+".java"))
						{
							allclass.add(o.getOwener()+".java");
						}

						if(o instanceof CreateOperationRefinement)
						{
							CreateOperationRefinement croprf=(CreateOperationRefinement) o;
							allmethods.add(croprf.getName()+"::"+croprf.getOwner());
							allclass.add(croprf.getOwner()+".java");
						}
					}

					if(st.getPrimitive() instanceof CreateAttribute )
					{	
						CreateAttributeImpl o=(CreateAttributeImpl) st.getPrimitive();
						allattributtes.add(o.getName()+"::"+o.getOwner()+".java");
						if(!allclass.contains(o.getOwner()+".java"))
						{
							allclass.add(o.getOwner()+".java");
						}
					}
					//methode pour les contenues des methode

					if(st.getPrimitive() instanceof CreateStatement )
					{	
						CreateStatementImpl o=(CreateStatementImpl) st.getPrimitive();
						FeatureToCode.allStatements.add(o.getText());
						if(!allclass.contains(o.getOwnerClass()+".java"))
						{
							allclass.add(o.getOwnerClass()+".java");
						}

						if(!allmethods.contains(o.getOwnerOperation()+"::"+o.getOwnerClass()+".java"))
						{
							allmethods.add(o.getOwnerOperation()+"::"+o.getOwnerClass()+".java");
						}

						if(o.getOwnerBlock() instanceof CreateStatement)
						{
							CreateStatement current = o;
							do
							{
								current = (CreateStatement)current.getOwnerBlock();
								if(!allStatements.contains(current.getText()))
									if(!allStatementsAjout.contains(current.getText()))
										allStatementsAjout.add(current.getText());
									else 
										break; // fin du while car si il existe, alors ses statement père existe aussi 
							}while(current.getOwnerBlock() instanceof CreateStatement);
						}
					}
				}
			}
			catch(Exception e)
			{
				System.out.println(e.getMessage());
			}
		}
		first=true;
		return true;
	}

	public static void getAllClassNamesInFeatureBase(Feature base)
	{     
		try
		{
			featureBase = base;
			allMethdeBase.clear();
			allStatementsBase.clear();
			for(Trigger t : base)
			{
				StatementPrimitive st = (StatementPrimitive)t;
				if(st.getPrimitive() instanceof CreateStatement )
				{	
					CreateStatementImpl o=(CreateStatementImpl) st.getPrimitive();
					allStatementsBase.add(o.getText());
					if(!allMethdeBase.contains(o.getOwnerOperation()+"::"+o.getOwnerClass()+".java"))
					{
						allMethdeBase.add(o.getOwnerOperation()+"::"+o.getOwnerClass()+".java");
					}
				}
			}
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}

	/**
	 * Vérifie s'il existe une statement
	 * @param st : Statemeent
	 * @return boolean
	 */
	public boolean existStatement(Statement st)
	{
		ReadXmiFHJava reader = new ReadXmiFHJava();
		String text = reader.getStatement(st);
		if(st instanceof VariableDeclaration)
			return true;
		return (allStatements.contains(text) || allStatementsAjout.contains(text));
	}

	/**
	 * Vérifie s'il existe une statement
	 * @param st : Statemeent
	 * @return boolean
	 */
	public boolean existStatementAjout(Statement st)
	{
		ReadXmiFHJava reader = new ReadXmiFHJava();
		String text = reader.getStatement(st);
		if(st instanceof VariableDeclaration)
			return true;
		return allStatementsAjout.contains(text);
	}

	/**
	 * Vérifie s'il existe une statement
	 * @param st : Statemeent
	 * @return boolean
	 */
	public boolean existStatementAjout(Object e)
	{
		if(e instanceof Statement){
			Statement s = (Statement) e;
			return existStatementAjout(s);
		}
		return false;
	}

	/**
	 *fonction qui teste et modifie isoriginal 
	 *
	 * */
	public boolean isOriginal(Statement stat)
	{
		if(currentfeature.getId().equals("F0")){
			return false;
		}
		ReadXmiFHJava reader = new ReadXmiFHJava();
		String text = reader.getStatement(stat);
		if(allStatementsBase.contains(text)){
			if(isoriginal) return !(isoriginal=!isoriginal);
			return false;
		}
		return false;
	}
	/**
	 * Debug
	 * @param classname
	 * @return
	 */
	public boolean thisCompilationUnitinfeatur(String classname) 

	{
		String res[]=classname.split("::");	
		currentclass=res[0];
		return (allclass.contains(res[0].trim()) 
				|| allinterface.contains(res[0].trim())) ? true : false;
	}

	/**
	 * Est une Feature
	 * @return boolean
	 */
	public boolean isBaseFeature()
	{
		return currentfeature.getId().equals(feautreName);
	}

	/**
	 * Cette attribut est dans la feature ?
	 * @param attributteName : nom de l'attribut
	 * @return true if(list.contains(attributName)) 
	 */
	public boolean thisattributteinfeature(String attributteName)
	{
		attributteName = attributteName+"::"+currentclass;
		return allattributtes.contains(attributteName) ? true : false;
	}

	/**
	 * Il existe cette Méthode dans la Feature ?
	 * @param Methodname : nom de la méthode
	 * @return true si la class contient cette méthode
	 */
	public boolean thisMethodinfeature(String Methodname)
	{
		String res[]=Methodname.split("::");
		if(res.length>1)
			return true;
		Methodname=res[0]+"::"+currentclass;
		if(featureBase != null && allmethods.contains(Methodname) && allMethdeBase.contains(Methodname))
			isoriginal=true;
		else isoriginal=false;
		return allmethods.contains(Methodname) ? true : false;
	}

	/**
	 * Il existe cette Interface dans la Feature
	 * @param interfacename : nom de l'interface
	 * @return boolean
	 */
	public boolean thisInterfaceinfeature(String interfacename)
	{
		String res[]=interfacename.split("::");
		currentclass=res[0];
		return allinterface.contains(res[0].trim()) ? true : false;
	}
}
